package nl.unimaas.micc.umsnooker.simulation;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.LogManager;

import nl.unimaas.micc.umsnooker.domain.BilliardBall;
import nl.unimaas.micc.umsnooker.domain.Cue;
import nl.unimaas.micc.umsnooker.domain.Table;
import nl.unimaas.micc.umsnooker.math.BairstowSolver;
import nl.unimaas.micc.umsnooker.simulation.event.BallCollision;
import nl.unimaas.micc.umsnooker.simulation.event.CueInteraction;
import nl.unimaas.micc.umsnooker.simulation.event.Event;
import nl.unimaas.micc.umsnooker.simulation.physics.Physics;

import com.jme.math.Vector3f;

import junit.framework.TestCase;

public class InTimeSimulationBenchmarkBreakoff extends TestCase
{
	private Set<BilliardBall> balls;
	private Table table;
	private Set<Event> initEvents;
	private BilliardBall cueBall;
	private Cue cue;

	@Override
	protected void setUp() throws Exception
	{
    	try
		{
			LogManager.getLogManager().readConfiguration(new FileInputStream("logging.properties"));
		}
		catch (SecurityException e)
		{
			e.printStackTrace();
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		super.setUp();

		table = new Table(1.778f, 3.569f, .737f, .292f, .324f, .0525f / 2f,
				.045f, .045f);

		// --> Initialize the cue ball
		Vector3f cueBallPosition = new Vector3f(table.getBrownSpot().x
				+ table.getDRadius() / 2f, table.getBrownSpot().y
				- table.getDRadius() / 2f, 0);
		cueBall = new BilliardBall(0, BilliardBall.Type.CUE, cueBallPosition);
		// We store all balls in a List:
		balls = new HashSet<BilliardBall>(25);
		balls.add(cueBall);

		// --> Initialize the colored balls
		balls.add(new BilliardBall(2, BilliardBall.Type.YELLOW, table
				.getYellowSpot()));
		balls.add(new BilliardBall(3, BilliardBall.Type.GREEN, table
				.getGreenSpot()));
		balls.add(new BilliardBall(4, BilliardBall.Type.BROWN, table
				.getBrownSpot()));
		balls.add(new BilliardBall(5, BilliardBall.Type.BLUE, table
				.getBlueSpot()));
		balls.add(new BilliardBall(6, BilliardBall.Type.PINK, table
				.getPinkSpot()));
		balls.add(new BilliardBall(7, BilliardBall.Type.BLACK, table
				.getBlackSpot()));

		// --> Initialize the red balls
		int id = 8;
		for (Vector3f redSpot : table.getRedSpots())
		{
			balls.add(new BilliardBall(id++, BilliardBall.Type.RED, redSpot));
		}

		// --> Configure all balls
		for (BilliardBall ball : balls)
		{
			ball.setRadius(table.getBallRadius());
			ball.setMass(.120f);
			ball.setFriction(0.06f);
			ball.setTime(0);
		}

		BairstowSolver.THRESHOLD = 5E-6;
		Simulation.TIME_THRESHOLD = 1E-7;
		Simulation.SPACE_THRESHOLD = 1E-6;
		BallCollision.VELOCITY_THRESHOLD = 1E-8f;
		Physics.THRESHOLD = 5E-6;
	}

	class EventCounter implements EventHandler{

		private int eventNumber = 0;
		@Override
		public void handle(Event e) {
				eventNumber++;			
		}
		
		private int getNumber(){
			return eventNumber;
		}
	}
	public void testSimulation()
	{
		float velocity = .5f;
		float step = .25f;
		float maxValue = 10f;
		while(velocity <= maxValue){
			
			int runs = 100;
			
			long time = System.currentTimeMillis();
			Simulation sim = new InTimeSimulation(balls, table);
			EventCounter counter = new EventCounter();
			sim.addEventHandler(counter);
			
			for (int i = 0; i < runs; i++)
			{
				initEvents = new HashSet<Event>();
				initEvents.add(new CueInteraction(0, cue, cueBall, 0, 0, 0, 0, velocity));
				sim.init(initEvents);
				sim.finish();
				//sim.reset();
			}
			float result = (System.currentTimeMillis() - time) / 1000f;
			int eventCount = counter.getNumber();
			System.out.println(runs + " runs in " + result + "s : "
					+ (runs / result) + "runs/s at velocity " + velocity + "\n Event count: " + eventCount / runs);
			velocity += step;
		}
	}

}
